package com.yc.cloud.admin.service.impl;

import com.yc.cloud.common.orm.CommonPage;
import com.yc.cloud.admin.dto.request.HwDeviceCreateReqDTO;
import com.yc.cloud.admin.dto.request.HwDeviceUpdateReqDTO;
import com.yc.cloud.admin.vo.HwDeviceVo;
import com.yc.cloud.entity.HwDevice;
import com.yc.cloud.entity.HwDeviceCamera;
import com.yc.cloud.entity.HwCamera;
import com.yc.cloud.admin.vo.HwCameraVo;
import com.yc.cloud.mapper.HwDeviceMapper;
import com.yc.cloud.admin.service.HwCameraService;
import com.yc.cloud.admin.service.HwDeviceCameraService;
import com.yc.cloud.mapper.HwDeviceCameraMapper;
import com.yc.cloud.admin.service.HwDeviceService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yc.cloud.common.basic.dto.BasePageReqDTO;
import com.yc.cloud.admin.dto.request.HwDeviceRegisterReqDTO;
import com.yc.cloud.admin.dto.request.HwDevicePageReqDto;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import com.yc.cloud.admin.config.StreamProperties;
import jakarta.annotation.Resource;

import java.util.Objects;
import java.util.List;
import java.util.ArrayList;
import java.util.stream.Collectors;
import com.yc.cloud.api.enums.HWDeviceStatus;
import com.yc.cloud.api.enums.HwDeviceType;
import com.yc.cloud.mapper.HwDeviceCameraMapper;

/**
 * <p>
 * 硬件设备表 (AI盒子) 服务实现类
 * </p>
 *
 * @author kinggu
 * @since 2025-07-15
 */
@Service
@Slf4j
public class HwDeviceServiceImpl extends ServiceImpl<HwDeviceMapper, HwDevice> implements HwDeviceService {

    @Resource
    private StreamProperties streamProperties;

    @Resource
    private HwDeviceCameraMapper hwDeviceCameraMapper;

    @Resource
    private HwDeviceCameraService hwDeviceCameraService;

    @Resource
    private HwCameraService hwCameraService;

    @Resource
    private com.yc.cloud.admin.service.HwDeviceGroupService hwDeviceGroupService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public HwDeviceVo register(HwDeviceRegisterReqDTO dto) {
        log.info("设备注册请求DTO:{}", dto);
        // 根据SN查询设备
        HwDevice device = this.getByDeviceSn(dto.getDeviceSn());

        if (Objects.nonNull(device)) {
            // 如果设备存在，则更新IP
            device.setDeviceIp(dto.getDeviceIp());
            device.setDeviceType(dto.getDeviceType());
            this.updateById(device);
            return this.convertToVo(device);
        } else {
            // 如果设备不存在，则创建新设备
            HwDevice newDevice = new HwDevice();
            newDevice.setName("设备" + dto.getDeviceSn());
            newDevice.setStatus(HWDeviceStatus.ONLINE.getCode()); // 初始状态为在线
            newDevice.setDeviceSn(dto.getDeviceSn());
            newDevice.setDeviceIp(dto.getDeviceIp());
            newDevice.setDeviceType(dto.getDeviceType()); // 默认为边缘设备
            this.save(newDevice);
            return this.convertToVo(newDevice);
        }
    }

    @Override
    public HwDevice getByDeviceSn(String deviceSn) {
        return this.getOne(new QueryWrapper<HwDevice>().eq(HwDevice.DeviceSn, deviceSn));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean create(HwDeviceCreateReqDTO createReqDTO) {
        HwDevice entity = new HwDevice();
        BeanUtils.copyProperties(createReqDTO, entity);
        
        // 如果前端没有传 deviceType，则使用默认值 EDGE_DEVICE
        if (entity.getDeviceType() == null) {
            entity.setDeviceType(HwDeviceType.EDGE_DEVICE.getCode());
        }
        
       // generateRtspUrl(entity);
        return save(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(HwDeviceUpdateReqDTO updateReqDTO) {
        HwDevice entity = new HwDevice();
        BeanUtils.copyProperties(updateReqDTO, entity);
        
        // 如果前端没有传 deviceType，则使用默认值 EDGE_DEVICE
        if (entity.getDeviceType() == null) {
            entity.setDeviceType(HwDeviceType.EDGE_DEVICE.getCode());
        }
        
        // 需要根据摄像头信息,生成新的rtspurl
        //generateRtspUrl(entity);
        return updateById(entity);
    }

    @Override
    public CommonPage<HwDeviceVo> list(HwDevicePageReqDto pageReqDTO) {
        QueryWrapper<HwDevice> queryWrapper = new QueryWrapper<>();

        // 精确匹配查询
        if (Objects.nonNull(pageReqDTO.getGroupId())) {
            queryWrapper.eq(HwDevice.GroupId, pageReqDTO.getGroupId());
        }
        if (Objects.nonNull(pageReqDTO.getStatus())) {
            queryWrapper.eq(HwDevice.Status, pageReqDTO.getStatus());
        }
        if (Objects.nonNull(pageReqDTO.getDeviceType())) {
            queryWrapper.eq(HwDevice.DeviceType, pageReqDTO.getDeviceType());
        }

        // 全局关键字模糊查询
        if (StrUtil.isNotBlank(pageReqDTO.getKeyword())) {
            queryWrapper.and(wq -> wq.like(HwDevice.Name, pageReqDTO.getKeyword())
                    .or().like(HwDevice.DeviceSn, pageReqDTO.getKeyword())
//                    .or().like(HwDevice.CameraIp, pageReqDTO.getKeyword())
                    .or().like(HwDevice.Location, pageReqDTO.getKeyword()));
        }

        // 排序：优先按是否置顶、置顶时间倒序，再按创建时间倒序
        if (Boolean.TRUE.equals(pageReqDTO.getPinnedSort())) {
            // 在线摄像头优先，其次置顶与置顶时间，最后更新时间
            queryWrapper
                .orderByDesc(HwDevice.IsPinned)
//                .orderByDesc(HwDevice.CameraOnlineStatus)
                .orderByDesc(HwDevice.PinnedTime)
                .orderByDesc(HwDevice.UPDATE_TIME);
        }else {
            if (Objects.equals(BasePageReqDTO.ORDER_DESC, pageReqDTO.getOrder())) {
                queryWrapper.orderByDesc(StrUtil.toUnderlineCase(pageReqDTO.getSortBy()));
            } else {
                queryWrapper.orderByAsc(StrUtil.toUnderlineCase(pageReqDTO.getSortBy()));
            }
        }
        
        // 根据 page 参数决定是否分页
        if (Boolean.TRUE.equals(pageReqDTO.getPage())) {
            Page<HwDevice> page = new Page<>(pageReqDTO.getPageNum(), pageReqDTO.getPageSize());
            IPage<HwDevice> dbPage = baseMapper.selectPage(page, queryWrapper);
            return CommonPage.restPage(dbPage.convert(this::convertToVo));
        } else {
            List<HwDevice> allRecords = baseMapper.selectList(queryWrapper);
            CommonPage<HwDeviceVo> result = new CommonPage<>();
            result.setList(convertToVoList(allRecords));
            result.setTotal((long) allRecords.size());
            result.setPageNum(1);
            result.setPageSize(allRecords.size());
            result.setTotalPage(1);
            return result;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean pin(Long id) {
        HwDevice update = new HwDevice();
        update.setId(id);
        update.setPinned(Boolean.TRUE);
        update.setPinnedTime(java.time.LocalDateTime.now());
        return updateById(update);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean unpin(Long id) {
        HwDevice update = new HwDevice();
        update.setId(id);
        update.setPinned(Boolean.FALSE);
        update.setPinnedTime(null);
        return updateById(update);
    }

    @Override
    public HwDeviceVo getVOById(Long id) {
        HwDevice entity = getById(id);
        return convertToVo(entity);
    }

    @Override
    public List<HwDeviceVo> convertToVoList(List<HwDevice> entityList) {
        if (entityList == null) {
            return null;
        }
        return entityList.stream()
                .map(this::convertToVo)
                .collect(Collectors.toList());
    }

    private HwDeviceVo convertToVo(HwDevice entity) {
        if (entity == null) {
            return null;
        }
        HwDeviceVo vo = new HwDeviceVo();
        BeanUtils.copyProperties(entity, vo);
        return vo;
    }

  

    @Override
    public HwDevice get(Long id) {
        return getById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(Long id) {
        return removeById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean unbindDevicesFromGroup(Long groupId) {
        return lambdaUpdate()
                .eq(HwDevice::getGroupId, groupId)
                .set(HwDevice::getGroupId, null)
                .update();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean bindDevicesToGroup(Long groupId, List<Long> deviceIds) {
        if (deviceIds == null || deviceIds.isEmpty()) {
            return true;
        }
        return lambdaUpdate()
                .in(HwDevice::getId, deviceIds)
                .set(HwDevice::getGroupId, groupId)
                .update();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean bindCameras(Long deviceId, List<Long> cameraIds) {
        if (cameraIds == null || cameraIds.isEmpty()) {
            return true;
        }

        // 先解绑已存在的关系，避免重复绑定
        hwDeviceCameraMapper.clearExistingBindings(deviceId, cameraIds);

        // 批量创建新的绑定关系
        List<HwDeviceCamera> deviceCameras = cameraIds.stream()
            .map(cameraId -> {
                HwDeviceCamera deviceCamera = new HwDeviceCamera();
                deviceCamera.setDeviceId(deviceId);
                deviceCamera.setCameraId(cameraId);
                return deviceCamera;
            })
            .collect(Collectors.toList());
        
        // 使用MyBatis-Plus的saveBatch批量插入
        if (!deviceCameras.isEmpty()) {
            hwDeviceCameraService.saveBatch(deviceCameras);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean unbindCameras(Long deviceId) {
        // 将设备下的所有绑定关系设为已解绑状态
        return hwDeviceCameraMapper.unbindAllCamerasByDevice(deviceId) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean unbindSpecificCameras(Long deviceId, List<Long> cameraIds) {
        if (cameraIds == null || cameraIds.isEmpty()) {
            return true;
        }
        return hwDeviceCameraMapper.unbindCameras(deviceId, cameraIds) > 0;
    }

    @Override
    public List<Long> getBoundCameraIds(Long deviceId) {
        return hwDeviceCameraMapper.selectCameraIdsByDeviceId(deviceId);
    }

    @Override
    public List<HwCameraVo> getBoundCameras(Long deviceId) {
        // 先获取摄像头ID列表
        List<Long> cameraIds = hwDeviceCameraMapper.selectCameraIdsByDeviceId(deviceId);
        
        if (cameraIds == null || cameraIds.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 使用MyBatis-Plus的批量查询，避免N+1查询问题
        List<HwCamera> cameras = hwCameraService.listByIds(cameraIds);
        
        // 转换为VO对象
        return hwCameraService.convertToVoList(cameras);
    }

    @Override
    public boolean isCameraBound(Long deviceId, Long cameraId) {
        return hwDeviceCameraMapper.existsBinding(deviceId, cameraId);
    }

    @Override
    public boolean refreshData() {
        log.info("开始刷新设备列表数据和分组统计信息");
        try {
            // 这里可以添加需要刷新的缓存清理逻辑
            // 比如清理设备在线状态缓存、分组统计缓存等
            
            // 同时触发设备分组数据的刷新
            hwDeviceGroupService.refreshData();
            
            // 返回成功，前端会重新调用列表查询接口获取最新数据
            // 这样确保设备列表和分组信息都是最新的
            log.info("设备数据和分组信息刷新完成");
            return true;
        } catch (Exception e) {
            log.error("刷新设备数据失败", e);
            return false;
        }
    }

}
